﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Newtonsoft.Json;
using UnityEditor;

public class OneKeyBuildAssetBundle : EditorWindow
{
    #region config

    /// <summary>
    /// 放于Resources目录下
    /// </summary>
    public static string ConfigFilePath = "Assets/_Gate/Resources/bundleFileConfig.json";

    public static int EachBundleCapacity = 10;

    public static string OutputBundleFilePath = "Assets/_Gate/Resources/BundleFiles";

    public static string[] paths = new string[]
    { 
        "Assets/_Gate/Anim/resources/Buff",
        "Assets/_Gate/Anim/resources/Cosplay/Avatar",
        "Assets/_Gate/Anim/resources/Cosplay/Title",
        "Assets/_Gate/Anim/resources/Enermy",
        "Assets/_Gate/Anim/resources/Hero",
        "Assets/_Gate/Anim/resources/Proj",
        "Assets/_Gate/Anim/resources/SFX",
        "Assets/_Gate/Anim/resources/UI", 
    };


    #endregion

    #region window code

    [MenuItem("Coser/ONE_KEY_BUNDLEFILE")]
    public static void InitWindow()
    {
        EditorWindow.GetWindow<OneKeyBuildAssetBundle>();
    }

    public OneKeyBuildAssetBundle()
    {
        //TODO: initialize
        _ConfigFile = Resources.Load<TextAsset>(ConfigFilePath);
        _Assets = _ConfigFile ? Deserialize<List<ResourceConfigTool.Asset>>(_ConfigFile.text) : new List<ResourceConfigTool.Asset>();

        if (!Directory.Exists(OutputBundleFilePath))
        {
            Directory.CreateDirectory(OutputBundleFilePath);
        }

    }

    private void OnGUI()
    {
        EditorGUILayout.BeginHorizontal();
        Target = (BuildTarget)EditorGUILayout.EnumPopup(Target);

        _SharedShader = (Shader)EditorGUILayout.ObjectField("Shared Shader:", _SharedShader, typeof(Shader), false);

        if (GUILayout.Button("Clear Config and Data"))
        {
            // delete exists file
            DeleteExistAssetBundles();

            _Assets.Clear();

            SaveContentToFile(string.Empty, ConfigFilePath);
        }

        EditorGUILayout.EndHorizontal();

        // Classify the assets from selection
        if (GUILayout.Button("Classify File"))
        {
            _Assets.Clear();
            if (_Assets.Count == 0)
            {
                var targets = Selection.GetFiltered(typeof(GameObject), SelectionMode.Assets).ToList();
                if (targets.Count == 0)
                {
                    Debug.Log("<color=green> Will load assets from default config</color>");
                    foreach (var path in paths)
                    {
                        var files = Directory.GetFiles(path);
                        for (int index = 0; index < files.Length; index++)
                        {
                            var file = files[index];
                            file = file.Replace('\\', '/');
                            Debug.Log("load file @:" + file);

                            var tar = AssetDatabase.LoadAssetAtPath(file, typeof(GameObject)) as GameObject;
                            if (tar)
                            {
                                targets.Add(tar);
                            }

                        }
                    }
                }
                Debug.Log("Selected Assets Count:" + targets.Count);
                targets.Sort((a, b) => a.name.CompareTo(b.name));
                string bundleFileName = string.Empty;
                for (int i = 0; i < targets.Count; i++)
                {
                    var target = targets[i];
                    Debug.Log("Classifying:" + target.name);
                    if (i % EachBundleCapacity == 0)
                    {
                        bundleFileName = target.name + "_" + i;
                    } 
                    var asset = new ResourceConfigTool.Asset()
                    {
                        ShortName = target.name,
                        AssetBundleFileName = bundleFileName,
                        AssetName = target.name,
                        AssetType = typeof(GameObject).Name,
                        FullPath = AssetDatabase.GetAssetPath(target),
                        ObtainMethod = "packageBundle",
                    };
                    _Assets.Add(asset);


                }

                SaveContentToFile(Serialize(_Assets), ConfigFilePath);
            }

        }

        if (GUILayout.Button("ONE KEY!"))
        {
            // delete exists file
            DeleteExistAssetBundles();

            var assetsDic = _Assets.GroupBy(t => t.AssetBundleFileName, t => t).ToList();
            for (int index = 0; index < assetsDic.Count; index++)
            {
                var assetsList = assetsDic[index];
                var path = Path.Combine(OutputBundleFilePath, assetsList.Key) + ".bytes";
                if (EditorUtility.DisplayCancelableProgressBar(assetsList.Key, path, index / (float)assetsDic.Count))
                {
                    break;
                }
                Object[] selection =
                    assetsList.Select(asset => AssetDatabase.LoadAssetAtPath(asset.FullPath, typeof(GameObject)))
                        .ToArray();

                BuildPipeline.BuildAssetBundle(_SharedShader, selection, path,
                    BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets, Target);
            }
            EditorUtility.ClearProgressBar();

            AssetDatabase.Refresh();
        }
        GUI.color = Color.green;
        EditorGUILayout.BeginVertical();

        foreach (var path in paths)
        {
            EditorGUILayout.LabelField(path);
        }
        EditorGUILayout.EndVertical();


    }

    private static void DeleteExistAssetBundles()
    {
        var fileNames = Directory.GetFiles(OutputBundleFilePath);
        foreach (var fileName in fileNames)
        {
            Debug.Log("~Deleting:" + fileName);
            File.Delete(fileName);
        }
        AssetDatabase.Refresh();
    }

    #endregion

    #region fields

    private TextAsset _ConfigFile;

    private List<ResourceConfigTool.Asset> _Assets;

    private Shader _SharedShader = Shader.Find("Spine/Skeleton");



#if UNITY_ANDROID
    private BuildTarget target = BuildTarget.Android;
#elif  UNITY_STANDALONE_WIN
	private BuildTarget target = BuildTarget.StandaloneWindows;
#elif UNITY_IPONE || UNITY_IOS || UNITY_IOS_API
	private BuildTarget target = BuildTarget.iOS;
#endif
    public BuildTarget Target
    {
        get { return target; }
        set
        {
            if (value != target)
            {
                target = value;
                //TODO:
            }
        }
    }


    #endregion

    #region private json serializer wrapper

    private T Deserialize<T>(string content)
    {
        return JsonConvert.DeserializeObject<T>(content);
    }

    private string Serialize(object obj)
    {
        return JsonConvert.SerializeObject(obj);
    }

    private void SaveContentToFile(string content, string filePath)
    {
        Debug.Log("<color=blue>Save file to " + filePath + "</color>");
        using (StreamWriter sw = new StreamWriter(filePath, false, new UTF8Encoding(false)))
        {
            sw.Write(content);
        }
        //AssetDatabase.Refresh();
    }


    #endregion
}
